from fastapi import FastAPI, Depends, Request
from fastapi.staticfiles import StaticFiles
from fastapi.responses import JSONResponse
from fastapi.middleware.cors import CORSMiddleware
from fastapi.exceptions import RequestValidationError
from pydantic import ValidationError
from contextlib import asynccontextmanager
from api.database import engine, Base, SessionLocal
# 导入模型包，它会自动通过 api/model/__init__.py 加载所有模型
from api.model import *
from api.controller import users, auth, ws, email_accounts, emails, drafts, proxies, webauthn, upload, translate, link_safety, singbox
from api.utils.response import fail
from api.utils.logger import get_logger
from api.utils.admin_init import init_admin_account
import uvicorn
import os
import time
from pathlib import Path
from dotenv import load_dotenv

# 设置应用时区为上海
os.environ['TZ'] = 'Asia/Shanghai'
time.tzset()

# 加载环境变量文件（从项目根目录）
env_path = Path(__file__).parent.parent / ".env"
if env_path.exists():
    load_dotenv(dotenv_path=env_path)
    logger = get_logger("main")
    logger.info(f"已加载环境变量文件: {env_path}")

# 初始化日志
logger = get_logger("main")

# 从环境变量读取配置
APP_NAME = "Web邮箱系统"
SECRET_KEY = os.getenv("SECRET_KEY", "your-super-secret-key-change-this-in-production")

# 确保必要目录存在
os.makedirs("uploads/avatars", exist_ok=True)
os.makedirs("uploads/images", exist_ok=True)
os.makedirs("emails", exist_ok=True)
os.makedirs("runtime/logs", exist_ok=True)
os.makedirs("runtime/cache", exist_ok=True)
os.makedirs("runtime/files", exist_ok=True)

# 检查并初始化数据库
def check_and_init_database():
    """检查数据库是否存在，不存在则自动创建"""
    from api.database import DB_TYPE
    
    # 仅对SQLite数据库进行文件检查
    if DB_TYPE == "sqlite":
        db_path = os.getenv("DB_PATH", "./usermails.db")
        db_exists = os.path.exists(db_path)
        
        if not db_exists:
            logger.info(f"数据库文件不存在: {db_path}")
            logger.info("正在自动创建数据库...")
            
            try:
                # 创建所有表
                Base.metadata.create_all(bind=engine)
                logger.info("数据库创建成功！")
                
                # 打印创建的表信息
                tables = Base.metadata.tables.keys()
                logger.info(f"已创建 {len(tables)} 个表: {', '.join(tables)}")
                
            except Exception as e:
                logger.error(f"数据库创建失败: {e}", exc_info=True)
                raise
        else:
            logger.info(f"数据库文件已存在: {db_path}")
            # 确保表结构存在（可能是旧数据库）
            Base.metadata.create_all(bind=engine)
    else:
        # MySQL/PostgreSQL 直接创建表（如果不存在）
        logger.info(f"使用 {DB_TYPE} 数据库，检查表结构...")
        Base.metadata.create_all(bind=engine)
        logger.info("数据库表结构检查完成")

# 执行数据库检查和初始化
check_and_init_database()

# 初始化管理员账号
try:
    db = SessionLocal()
    init_admin_account(db)
    db.close()
except Exception as e:
    logger.error(f"管理员账号初始化失败: {e}")

# 应用生命周期管理
@asynccontextmanager
async def lifespan(app: FastAPI):
    """应用启动和关闭时的生命周期管理"""
    # 启动时执行
    logger.info("应用启动中...")
    
    # 初始化Sing-box服务（如果已安装）
    try:
        from api.service.singbox_process_manager import SingBoxProcessManager
        from api.service.singbox_manager import SingBoxManager
        from api.service.singbox_config_manager import init_singbox_configs
        import time
        
        # 检查是否安装
        installed, version = SingBoxManager.check_singbox_installed()
        if installed:
            logger.info(f"检测到Sing-box {version}，正在初始化...")
            
            # 步骤1：先从数据库恢复代理配置到配置文件
            logger.info("步骤1：从数据库恢复代理配置...")
            db = SessionLocal()
            try:
                init_singbox_configs(db)
            finally:
                db.close()
            
            # 等待配置文件写入完成
            logger.info("等待配置文件写入完成...")
            time.sleep(1)
            
            # 验证配置文件完整性
            config_file = Path("runtime/singbox/service_config.json")
            if config_file.exists():
                try:
                    import json
                    with open(config_file, 'r') as f:
                        json.load(f)  # 验证JSON格式
                    logger.info("配置文件验证通过")
                except json.JSONDecodeError as e:
                    logger.error(f"配置文件格式错误: {e}")
                    raise
            
            # 步骤2：先停止旧进程，再启动新进程
            logger.info("步骤2：清理并重启Sing-box进程...")
            
            # 强制停止旧进程
            try:
                stop_success, stop_msg = SingBoxProcessManager.stop_process()
                if stop_success:
                    logger.info(f"✓ 旧进程已停止: {stop_msg}")
                else:
                    logger.warning(f"停止旧进程失败: {stop_msg}")
                time.sleep(1)  # 等待进程完全退出
            except Exception as e:
                logger.warning(f"停止旧进程时出错: {e}")
            
            # 启动新进程
            SingBoxProcessManager.initialize()
            
            # 验证进程是否真的启动了
            time.sleep(1)
            if SingBoxProcessManager._is_process_running():
                logger.info("✓ Sing-box服务启动成功")
            else:
                logger.error("✗ Sing-box进程启动失败")
        else:
            logger.info("Sing-box未安装，跳过启动")
    except Exception as e:
        logger.error(f"初始化Sing-box服务失败: {e}", exc_info=True)
    
    logger.info("FastAPI应用启动完成")
    logger.info("注意：邮件同步服务需要单独启动 (python3 -m api.sync_service)")

    yield

    # 关闭时执行
    logger.info("应用关闭中...")
    
    
    # 清理代理配置
    
    logger.info("FastAPI应用已关闭")

# 创建FastAPI应用
app = FastAPI(
    title=APP_NAME,
    description="多用户在线邮箱客户端服务API",
    version="1.0.0",
    root_path="/api",
    lifespan=lifespan
)

# Pydantic验证错误处理器
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
    """
    处理请求参数验证错误，返回统一格式
    """
    errors = exc.errors()
    if errors:
        # 提取第一个错误的详细信息
        first_error = errors[0]
        msg = first_error.get("msg", "验证失败")
        
        # 如果是自定义错误消息，直接使用
        if "Value error" in msg:
            msg = msg.replace("Value error, ", "")
        
        error_msg = msg
    else:
        error_msg = "请求参数验证失败"
    
    return JSONResponse(
        status_code=200,
        content=fail(msg=error_msg)
    )

# 全局异常处理器
@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
    # 对于所有未被特定异常处理器捕获的异常，都返回一个通用的JSON错误响应。
    # 这有助于防止敏感的服务器信息（如堆栈跟踪）泄露给客户端。
    logger.error(f"全局异常: {exc}", exc_info=True)
    return JSONResponse(
        status_code=200,
        content=fail(msg=f"服务器内部错误，请联系管理员")
    )

# 配置CORS - 允许所有来源
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# 挂载静态文件目录
app.mount("/uploads", StaticFiles(directory="uploads"), name="uploads")

# 注册路由
app.include_router(auth.router, prefix="/auth", tags=["authentication"])
app.include_router(users.router, prefix="/users", tags=["users"])
app.include_router(webauthn.router, prefix="/webauthn", tags=["webauthn"])
app.include_router(proxies.router, prefix="/proxies", tags=["proxies"])
app.include_router(singbox.router, prefix="/singbox", tags=["singbox"])
app.include_router(upload.router, prefix="/upload", tags=["upload"])
app.include_router(email_accounts.router, prefix="/email-accounts", tags=["email-accounts"])
# 翻译配置管理路由
app.include_router(translate.router, prefix="/translate", tags=["translate"])
# 邮件翻译路由（需要完整路径，所以再次注册到根路径）
app.include_router(translate.router, prefix="", tags=["translate-email"])
app.include_router(emails.router, prefix="/email-accounts/{account_id}/emails", tags=["emails"])
app.include_router(drafts.router, prefix="/email-accounts/{account_id}/drafts", tags=["drafts"])
app.include_router(link_safety.router, prefix="", tags=["link-safety"])
app.include_router(ws.router, prefix="", tags=["websockets"])

@app.get("/")
async def root():
    return {"message": f"欢迎使用 {APP_NAME}"}

@app.get("/health")
async def health_check():
    return {"status": "正常", "service": APP_NAME}

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=9999, reload=False)
